package yl.hs.bmipfull.security;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import yl.hs.bmipfull.utils.ResultCode;
import yl.hs.bmipfull.utils.Tl;
import yl.hs.bmipfull.viewmodels.WebResult;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

/**
 * @author 华砂信息 <br/>
 * 登陆拦截
 */
public class LoginFilter extends UsernamePasswordAuthenticationFilter {

    /**
     * 构造函数
     *
     * @param authenticationManager 认证管理器对象
     */
    public LoginFilter(AuthenticationManager authenticationManager) {
        setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
        setAuthenticationManager(authenticationManager);
    }

    /**
     * 输出信息到浏览器
     *
     * @param response
     * @param data
     * @throws IOException
     */
    public static void write(HttpServletResponse response, Object data) throws IOException {
        response.setContentType("application/json; charset=utf-8");
        // HttpResult.ok(data);
        WebResult result = new WebResult(ResultCode.SUCCESS, "ok", data);
        String json = Tl.toJson(result);
        response.getWriter().print(json);
        response.getWriter().flush();
        response.getWriter().close();
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        super.doFilter(request, response, chain);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String body = getBody(request);
        try {
            var data = Tl.jsonParse(body);
            String userName = "";
            String password = "";
            if (data.get("account") != null) {
                userName = data.get("account").toString().trim();
            }
            if (data.get("password") != null) {
                password = data.get("password").toString();
            }
            var authRequest = new AuthenticationToken(userName, password);
            setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        return super.attemptAuthentication(request, response);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        // 存储登录认证信息到上下文
        SecurityContextHolder.getContext().setAuthentication(authResult);
        // 记住我服务
        getRememberMeServices().loginSuccess(request, response, authResult);
        // 触发事件监听器
        if (this.eventPublisher != null) {
            eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }
        // 生成并返回token给客户端，后续访问携带此token
        AuthenticationToken token = new AuthenticationToken(null, null, TokenUtils.generateToken(authResult));
        write(response, token);
        super.successfulAuthentication(request, response, chain, authResult);
    }

    /**
     * 获取请求Body
     * @param request request
     * @return body
     */
    public String getBody(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
}
